package study.alex.resumedb.gae;

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.auth.oauth2.TokenResponseException;
import com.google.api.client.extensions.appengine.http.UrlFetchTransport;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.oauth2.Oauth2;
import com.google.api.services.oauth2.model.Userinfo;
import com.vaadin.server.ExternalResource;
import com.vaadin.server.Resource;

import java.io.IOException;
import java.io.Serializable;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Created with IntelliJ IDEA.
 * Author: Alexey Kuznetsov
 * Date: 08.03.14
 * Time: 12:41
 * SVN $Id$
 */
public class GoogleServices implements Serializable {
    private final static Logger log = Logger.getLogger(GoogleServices.class.getName());
    /**
     * Default transportation layer for Google Apis Java client.
     */
    private static final HttpTransport TRANSPORT = new UrlFetchTransport();

    /**
     * Default JSON factory for Google Apis Java client.
     */
    private static final JsonFactory JSON_FACTORY = new JacksonFactory();

    transient private Credential credential;
    private final String userId;

    public GoogleServices(String userId) {
        this.credential = getDiskCredentialForUser(userId);
        this.userId = userId;
    }

    public Credential getCredential() {
        return credential;
    }

    private Oauth2 getOauth2Service() {
        Oauth2 service = new Oauth2.Builder(TRANSPORT, JSON_FACTORY, credential)
                .setApplicationName("ResumeDB WS").build();
        return service;
    }

    private void readObject(java.io.ObjectInputStream stream)
            throws java.io.IOException, ClassNotFoundException
    {
        stream.defaultReadObject();

        // assign reference manually.

        credential = getDiskCredentialForUser(userId);
    }


    private Credential getDiskCredentialForUser(String id) {

        CredentialManager manager = CredentialManager.getInstance();

        if (manager == null || id == null) return null;

        try {
            if (manager.getStatus(id) == CredentialManager.GoogleDiskAccessStatus.GRANT) {
                Credential credential = manager.get(id);
                return credential;
            }
        } catch (IOException e) {
            log.log(Level.SEVERE, "Can't get credential from Datastore", e);
        }

        return null;
    }


    public Resource getUserIcon() {

        if (credential == null) return null;

        Oauth2 service = getOauth2Service();
        try {
            Userinfo about = service.userinfo().get().execute();
            String url = about.getPicture();
            log.fine("Picture URL from About service is " + url);
            return new ExternalResource(url);
        } catch (GoogleJsonResponseException e) {
            log.log(Level.WARNING, "Token revoked or it is otherwise bad", e);
            if (e.getStatusCode() == 401) {
                // The user has revoked our token or it is otherwise bad.
                // Delete the local copy so that their next page load will recover.
                try {
                    CredentialManager.getInstance().drop(userId);
                } catch (IOException e1) {
                    log.log(Level.SEVERE, "Exception when get User icon", e1);
                    return null;
                }
            }
            return null;
        } catch (TokenResponseException e) {
            log.log(Level.WARNING, "Token revoked or it is otherwise bad", e);
            try {
                CredentialManager.getInstance().drop(userId);
            } catch (IOException e1) {
                log.log(Level.SEVERE, "Exception when get User icon info", e1);
                return null;
            }
            return null;
        } catch (IOException e) {
            log.log(Level.SEVERE, "Exception when get User icon", e);
            return null;
        }
    }

    public String getUserName() {

        if (credential == null) return null;

        Oauth2 service = getOauth2Service();
        try {
            Userinfo about = service.userinfo().get().execute();
            String id = about.getName();
            log.fine("UserName from About service is " + id);
            return id;
        } catch (GoogleJsonResponseException e) {
            log.log(Level.WARNING, "Token revoked or it is otherwise bad", e);
            if (e.getStatusCode() == 401) {
                // The user has revoked our token or it is otherwise bad.
                // Delete the local copy so that their next page load will recover.
                try {
                    CredentialManager.getInstance().drop(userId);
                } catch (IOException e1) {
                    log.log(Level.SEVERE, "Exception when get about info", e1);
                    return null;
                }
            }
            return null;
        } catch (TokenResponseException e) {
            log.log(Level.WARNING, "Token revoked or it is otherwise bad", e);
            try {
                CredentialManager.getInstance().drop(userId);
            } catch (IOException e1) {
                log.log(Level.SEVERE, "Exception when get about info", e1);
                return null;
            }
            return null;
        } catch (IOException e) {
            log.log(Level.SEVERE, "Exception when get about info", e);
            return null;
        }
    }
}
